package com.yn.module.material.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yn.module.material.mapper.HospJointGroupMapper;
import com.yn.module.material.pojo.HospJointGroup;
import com.yn.module.material.pojo.JointGroupPart;
import com.yn.module.material.pojo.JointRet;
import com.yn.module.material.pojo.JointRetDetail;
import com.yn.module.material.service.HospJointGroupService;
import com.yn.module.material.service.JointRetDetailService;
import com.yn.module.material.service.JointRetService;
import com.yn.module.material.utils.StringUtils;
import com.yn.module.material.utils.constant.DataCache;
import com.yn.module.material.utils.enums.ConstEnum;
import com.yn.module.material.utils.xls.ExcelCheck;
import com.yn.module.material.utils.xls.ExcelCheckUtils;
import com.yn.module.material.utils.xls.ExcelDTO;
import com.yn.module.material.utils.xls.ExcelOperation;
import com.yn.module.material.utils.xls.entity.HospJointGroupEntity;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;


/**
 * HospJointGroupServiceImpl操作类
 *
 * @author 叶甯
 * @version 1.0.0
 * @date 2022-10-13 16:09:37
 */
@Service("hospJointGroupService")
@ExcelOperation(type = ConstEnum.ExcelEnum.MEDICARE_GROUP, importClz = HospJointGroupEntity.class)
public class HospJointGroupServiceImpl extends ServiceImpl<HospJointGroupMapper, HospJointGroup>
        implements HospJointGroupService {
    @Resource
    private ExcelCheckUtils excelCheckUtils;
    @Resource
    private JointRetDetailService jointRetDetailService;
    @Resource
    private JointRetService jointRetService;

    @Override
    public void checkExcel(Map<String, Object> selfParams, int headLines, ExcelDTO excelInfo, List<Object> list) {
        int length = list.size();
        List<String> errList = new ArrayList<>();
        // 导入数据按照编码进行唯一性判断
        Set<String> uniqueCheckedSet = new HashSet<>();
        for (int i = 0; i < length; i++) {
            HospJointGroupEntity item = (HospJointGroupEntity) list.get(i);
//            if (!ObjectUtils.isEmpty(item.getAmount()) && item.getAmount() < 0) {
//                errList.add("【数量】不允许为负数");
//            }
            if (ObjectUtils.isEmpty(item.getGoodsId()) && ObjectUtils.isEmpty(item.getMedicareCode())) {
                errList.add("【GOODS_ID、国家医保编码】至少存在一个");
            }
            //日期校验
            String out = item.getOut();
            if (out.length() < 8) {
                errList.add("【病人出院时间】的格式为yyyy-MM-dd");
            } else {
                Date date = DateUtil.parse(out, "yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd");
                if (DateUtil.compare(date, DateUtil.parse("2100-01-01", "yyyy-MM-dd")) > 0 ||
                        DateUtil.compare(date, DateUtil.parse("1950-01-01", "yyyy-MM-dd")) < 0) {
                    errList.add("【病人出院时间】的格式为yyyy-MM-dd,请检查格式和内容");
                }
                item.setOutTime(date);
            }

            excelCheckUtils.validatedExcelLineData(errList, uniqueCheckedSet,
                    new ExcelCheck().item(item).data(null).dataErrMsg("当前Excel存在相同的【药品代码】")
                            .length(length).headLines(headLines).current(i));
        }
    }

    @Override
    public void saveExcelData(Map<String, Object> selfParams, ExcelDTO dto, List<Object> list) throws Exception {
        if (ObjectUtils.isEmpty(list)) return;
        List<HospJointGroup> dataList = new ArrayList<>();
        List<JointRetDetail> retDetailList = new ArrayList<>();

        final String batchNo = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
        for (Object obj : list) {
            HospJointGroup entity = new HospJointGroup();
            BeanUtils.copyProperties((HospJointGroupEntity) obj, entity);
            entity.setEid(IdWorker.getIdStr());
            entity.setBatchNo(batchNo);
            entity.setAmount(entity.getAmount() == null ? 0 : entity.getAmount());
            entity.setUserId(StringUtils.obj2str(selfParams.get("userId")));
            dataList.add(entity);
        }
        // 数据重组
        Map<String, Map<String, Integer>> newDataMp = new HashMap<>(); // 存储部件ID和使用数量
        Map<String, Set<String>> newDataSet = new HashMap<>(); // 存储部件ID对应的组套编码
        data2New(dataList, newDataMp, newDataSet);
        // 组套校验
        Map<String, Integer> groupAmountMap = new HashMap<>(); // 存储当前使用的组套编码以及对应的使用量
        checkGroup(newDataMp, newDataSet, groupAmountMap);
        // 数据存储
        this.saveBatch(dataList);
        JointRet retMain = new JointRet();
        retMain.setEid(IdWorker.getIdStr());
        retMain.setBatchNo(batchNo);
        retMain.setUserId(StringUtils.obj2str(selfParams.get("userId")));
        retMain.setOrgId(StringUtils.obj2str(selfParams.get("orgId")));
        retMain.setAmountXls(list.size());
        for (Map.Entry<String, Integer> entry : groupAmountMap.entrySet()) {
            JointRetDetail jointRetDetail = new JointRetDetail();
            jointRetDetail.setEid(IdWorker.getIdStr());
            jointRetDetail.setPid(retMain.getEid());
            jointRetDetail.setBatchNo(retMain.getBatchNo());
            jointRetDetail.setOrgId(retMain.getOrgId());
            jointRetDetail.setGroupNo(entry.getKey());
            jointRetDetail.setAmountGroup(entry.getValue());
            retDetailList.add(jointRetDetail);
        }
        if (retDetailList.size() > 0) {
            int tmpTotal = 0;
            for (JointRetDetail tmp : retDetailList) {
                tmpTotal = tmpTotal + tmp.getAmountGroup();
            }
            retMain.setAmountJoint(tmpTotal);
            jointRetService.save(retMain);
            jointRetDetailService.saveBatch(retDetailList);
        }
    }

    /**
     * 数据重组
     *
     * @param dataList   待处理的原始数据
     * @param newDataMp  重组后的value为map的结果集
     * @param newDataSet 重组后value为set的结果集
     */
    private void data2New(List<HospJointGroup> dataList, Map<String, Map<String, Integer>> newDataMp, Map<String, Set<String>> newDataSet) {
        for (HospJointGroup data : dataList) {
            String key = data.getPatientId() + DateUtil.format(data.getOutTime(), DatePattern.PURE_DATE_PATTERN);
            Map<String, Integer> tmpMp = newDataMp.get(key);
            if (tmpMp == null) {
                tmpMp = new HashMap<>();
                newDataMp.put(key, tmpMp);
            }
            String partNo = ObjectUtils.isEmpty(data.getGoodsId()) ? DataCache.CacheGoodsId2PartNo.get(data.getMedicareCode())
                    : DataCache.CacheGoodsId2PartNo.get(data.getGoodsId());
            if (ObjectUtils.isEmpty(partNo)) continue;
            tmpMp.put(partNo, formatInteger(tmpMp.get(partNo)) + formatInteger(data.getAmount()));

            Set<String> tmpSet = newDataSet.get(key);
            if (tmpSet == null) {
                tmpSet = new HashSet<>();
                newDataSet.put(key, tmpSet);
            }
            if (!ObjectUtils.isEmpty(DataCache.CachePartNo2Group.get(partNo))) {
                tmpSet.addAll(DataCache.CachePartNo2Group.get(partNo));
            }
        }
    }

    /**
     * 组套校验
     */
    private void checkGroup(Map<String, Map<String, Integer>> newDataMp, Map<String, Set<String>> newDataSet, Map<String, Integer> groupAmountMap) {
        for (Map.Entry<String, Set<String>> entry : newDataSet.entrySet()) {
            // 当前用户本次住院的所有耗材，然后进行校验
            Map<String, Integer> patientUseMp = newDataMp.get(entry.getKey());
            Set<String> groupNoSet = entry.getValue();
            loop1:
            for (String groupNo : groupNoSet) {
                List<JointGroupPart> standPartList = DataCache.Cache_Std_Group2Part.get(groupNo);
                // 校验是否满足标准
                for (JointGroupPart tmp : standPartList) {
                    int tmpNum = formatInteger(patientUseMp.get(tmp.getPartNo())) - tmp.getNum();
                    if (tmpNum < 0) {
                        continue loop1;
                    }
                }
                // 对应满足标准的病人耗材用量进行削减
                for (JointGroupPart tmp : standPartList) {
                    patientUseMp.put(tmp.getPartNo(), patientUseMp.get(tmp.getPartNo()) - tmp.getNum());
                }
                // 将满足标准的数据添加到结果表
                groupAmountMap.put(groupNo, formatInteger(groupAmountMap.get(groupNo)) + 1);
            }
        }
    }


    private int formatInteger(Object obj) {
        if (obj == null) return 0;
        return Integer.valueOf(obj.toString());
    }
}